home *** CD-ROM | disk | FTP | other *** search
/ CD Ware Multimedia 1994 November / Cd Ware (Nro. 2) - Epimundo.iso / DOS / PG / STRX.ZIP / STR.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-06  |  25.0 KB  |  989 lines

  1. //
  2. // str.cpp : str class implementation
  3. // Author  : Roy S. Woll
  4. //
  5. // Copyright (c) 1993 by Roy S. Woll
  6. // You may distribute this source freely as long as you leave all files
  7. // in their original form, including the copyright notice as is.
  8. //
  9. //
  10. // Version 3.0      5/9/94
  11. //    Borland 4 compatibilty, ltostr, strtol
  12. //
  13. // Version 2.21     6/8/93
  14. //    Add itostr friend function
  15. //
  16. // Version 2.2          5/12/93
  17. //    Fixed substr assignment problem.  -->  str = substr
  18. //    Add member function read, lowercase,
  19. //    uppercase, and variations of pad and strip.
  20. // 
  21. // Version 2.11     3/17/93
  22. //    Friend operator ">>" changed to use str's buffer if > 256.
  23. //    Assign operator optimized to not copy referenced data.
  24. //    Fix - Remove member function now transfers only necessary characters
  25. //
  26. // Version 2.00     12/5/92
  27. //    Support searching/replacing, regular expressions, case sensitivity
  28. //
  29. //    Fixed the following bugs.
  30. //       1. Fixed size strings
  31. //       2. Concatenating a substr
  32. //
  33. //    Changed member functions pad/strip to modify instance, and introduced
  34. //    friend functions pad/strip.
  35. //
  36. // Version 1.00     10/20/92
  37. //
  38. #include <ctype.h>
  39. #include <string.h>
  40. #include <iostream.h>
  41. #include <iomanip.h>
  42. #include <assert.h>
  43. #include <stdlib.h>
  44. #include "str.h"
  45. #include "dynstream.h"
  46.  
  47. int strnicmp(const char * s1, const char * s2, unsigned n);
  48. int stricmp(const char * s1, const char * s2);
  49. char * strlwr(char *);
  50. char * strupr(char *);
  51.  
  52. inline int min(int x, int y){if (x<y) return x; else return y;}
  53. inline int max(int x, int y){if (x>y) return x; else return y;}
  54.  
  55. // Define macro used to adjust internal debugging counters for object
  56. #ifdef DEBUG_STR     
  57. #define STR_SUB_COUNTERS(count)   count--;
  58. #define STR_ADD_COUNTERS(count)   count++;Total##count++;
  59. #else
  60. #define STR_SUB_COUNTERS(count)
  61. #define STR_ADD_COUNTERS(count)
  62. #endif
  63.  
  64.  
  65. str::strdata str::NullData = {0, 0, 1, 0, 1, ""};
  66.  
  67. // Create and map to new buffer, and if previous buffer exists,
  68. //   transfer to new buffer.
  69. // Delete old buffer if unreferenced.
  70. char * str::getNewBuffer(int newbufsize){
  71.    return  getNewBuffer(length(), newbufsize);
  72. };
  73.  
  74. char * str::getNewBuffer(int len, int newbufsize)
  75. {
  76.    if (data==&NullData){
  77.      if (memsize_incr) newbufsize = max(newbufsize, memsize_init);
  78.      else newbufsize = memsize_init;
  79.    }
  80.    else {
  81.      if (!memsize_incr) return NULL;
  82.      if ((newbufsize>data->cursize) || (!newbufsize) )
  83.         newbufsize = max(newbufsize, data->cursize + memsize_incr);
  84.      else newbufsize = max(newbufsize, memsize_init);
  85.    }
  86.    if (!newbufsize) newbufsize = memsize_incr;       // don't allow 0 size
  87.  
  88.    strdata * newdata;
  89.    init(newdata, newbufsize, 0);
  90.    setNewBuffer(newdata, newbufsize, len);
  91.  
  92.    return data->buf;
  93. };
  94.  
  95. // Map to new buffer and if previous buffer exists, transfer to new buffer
  96. void str::setNewBuffer(strdata * newdata,
  97.            int newbufsize, int len){
  98.  
  99.    newdata->curlength = data->curlength;
  100.    newdata->strChange = data->strChange;
  101.  
  102.  
  103.    if (data->mystream) {
  104.  
  105.      // Use existing stream
  106.       newdata->mystream = data->mystream;
  107.  
  108.      // update existing stream to map to new buffer
  109.       newdata->mystream->rdbuf()->setNewBuffer(newdata->buf, newbufsize);
  110.  
  111.      // update stream length next time stream is called for previous data
  112.       if (!data->strChange){
  113.          data->strChange = 1;
  114.          data->curlength = data->mystream->rdbuf()->out_waiting();
  115.       };
  116.  
  117.      // force previous data to have unitialized stream
  118.       data->mystream = NULL;
  119.    };
  120.  
  121.    memcpy(newdata->buf, data->buf, len);
  122.  
  123.    if (!(--data->refcount)) {
  124.         delete data;
  125.         STR_SUB_COUNTERS(AllocationCount)
  126.    }
  127.  
  128.  
  129.    data = newdata;
  130. };
  131.  
  132.  
  133. void str::init(strdata*& adata, int cursize,
  134.           int curlength)
  135. {
  136.    STR_ADD_COUNTERS(AllocationCount)
  137.    if (!cursize) cursize=STR_DEFAULT_MEMINCR;
  138.  
  139.     adata =
  140.         (strdata *) new char [(cursize+1)+
  141.                             sizeof(strdata)-strdata::STR_DEBUG_BUFSIZE];
  142.     if (!adata){
  143.       cout << "Failed to allocate memory (" << cursize << ")" << endl;
  144.       assert(adata);
  145.    };
  146.  
  147.    adata->cursize=cursize;
  148.    adata->curlength=curlength;
  149.    adata->refcount=1;
  150.    adata->mystream=NULL;
  151.    adata->strChange=1;
  152. };
  153.  
  154.  
  155. // Construct an empty str
  156. str::str (void):
  157.           data(&NullData),
  158.           memsize_init(0), memsize_incr(STR_DEFAULT_MEMINCR),
  159.           flags(defaultFlags)
  160. {
  161.    STR_ADD_COUNTERS(ObjectCount)
  162.    data->refcount++;
  163. };
  164.  
  165. // Construct an empty str
  166. str::str (int p_bufsize, int p_incr):
  167.           data(&NullData),
  168.           memsize_init(p_bufsize), memsize_incr(p_incr),
  169.           flags(defaultFlags)
  170. {
  171.    STR_ADD_COUNTERS(ObjectCount)
  172.    data->refcount++;
  173. };
  174.  
  175.  
  176. // Construct a str containing substr, char *
  177. str::str (const char * s1, const char * s2):
  178.           memsize_init(0),memsize_incr(STR_DEFAULT_MEMINCR),
  179.           flags(defaultFlags)
  180. {
  181.  
  182.    STR_ADD_COUNTERS(ObjectCount)
  183.    int len1=(s1 ? strlen(s1) : 0);
  184.    int len2=(s2 ? strlen(s2) : 0);
  185.  
  186.    init(data, len1+len2, len1+len2);
  187.    memcpy(data->buf, s1, len1);
  188.    memcpy(data->buf+len1, s2, len2);
  189. };
  190.  
  191. // Construct a str containing char *, substr
  192. str::str (const char * s1, const substr& s2):
  193.           memsize_init(0),memsize_incr(STR_DEFAULT_MEMINCR),
  194.           flags(defaultFlags)
  195. {
  196.  
  197.    STR_ADD_COUNTERS(ObjectCount)
  198.    int len1=(s1 ? strlen(s1) : 0);
  199.    int len2=s2.length();
  200.  
  201.    init(data, len1+len2, len1+len2);
  202.    memcpy(data->buf, s1, len1);
  203.    memcpy(data->buf+len1, &s2.mystr->data->buf[s2.posReplace], len2);
  204. };
  205.  
  206. // Construct a str containing two char *
  207. str::str (const substr& s1, const char * s2):
  208.           memsize_init(0),memsize_incr(STR_DEFAULT_MEMINCR),
  209.           flags(defaultFlags)
  210. {
  211.  
  212.    STR_ADD_COUNTERS(ObjectCount)
  213.    int len1= s1.length();
  214.    int len2= (s2 ? strlen(s2) : 0);
  215.  
  216.    init(data, len1+len2, len1+len2);
  217.    memcpy(data->buf, &s1.mystr->data->buf[s1.posReplace], len1);
  218.    memcpy(data->buf+len1, s2, len2);
  219. };
  220.  
  221. // Construct a str containing two substr
  222. str::str (const substr& s1, const substr& s2):
  223.           memsize_init(0),memsize_incr(STR_DEFAULT_MEMINCR),
  224.           flags(defaultFlags)
  225. {
  226.  
  227.    STR_ADD_COUNTERS(ObjectCount)
  228.    int len1= s1.length();
  229.    int len2= s2.length();
  230.  
  231.    init(data, len1+len2, len1+len2);
  232.    memcpy(data->buf,      &s1.mystr->data->buf[s1.posReplace], len1);
  233.    memcpy(data->buf+len1, &s2.mystr->data->buf[s2.posReplace], len2);
  234. };
  235.  
  236. // Construct a str containing char *
  237. str::str (const char * s, int p_bufsize, int p_incr):
  238.           memsize_init(p_bufsize),memsize_incr(p_incr),
  239.           flags(defaultFlags)
  240. {
  241.    STR_ADD_COUNTERS(ObjectCount)
  242.    if (!s) return;
  243.  
  244.    int curlength, cursize;
  245.  
  246.    if (memsize_incr==0) {  // not allowed to expand
  247.       curlength = min(strlen(s), memsize_init);
  248.       cursize = memsize_init;
  249.    }
  250.    else {
  251.       curlength=strlen(s);
  252.       cursize = max(curlength, memsize_init);
  253.    };
  254.  
  255.    init(data, cursize, curlength);
  256.    memcpy(data->buf, s, curlength);
  257. };
  258.  
  259. // Construct a str containing str
  260. str::str (const str& s, int p_bufsize, int p_incr):
  261.           memsize_init(p_bufsize),memsize_incr(p_incr),
  262.           flags(defaultFlags)
  263. {
  264.    STR_ADD_COUNTERS(ObjectCount)
  265.  
  266.    if (memsize_incr) {
  267.       data = s.data;
  268.       data->refcount++;
  269.    }
  270.    else {
  271.       int curlength = min(s.length(), memsize_init);
  272.       init(data, memsize_init, curlength);
  273.       memcpy(data->buf, s, curlength);
  274.    };
  275.  
  276. };
  277.  
  278.  
  279. // Return a ostream that maps to the same buffer as the str
  280. ostream& str::stream(int pos){
  281.    return stream().seekp(pos);
  282. };
  283.  
  284. // Return a ostream that maps to the same buffer as the str
  285. ostream& str::stream(void){
  286.  
  287.   //
  288.   // check if need to allocate more memory
  289.   //
  290.    int allocsize=0;
  291.    if (data==&NullData) allocsize = memsize_init;    // first time allocating
  292.    else if (length()>=size()) allocsize = size()+memsize_incr;
  293.    _checkMemAllocation(allocsize);
  294.  
  295.   //
  296.   // Create stream if it doesn't exist
  297.   // otherwise tell dynstream about me in case it needs to extend buf
  298.   //
  299.    if (!data->mystream) data->mystream = new dynstream(this);
  300.    else data->mystream->rdbuf()->set_str(this);
  301.  
  302.  
  303.   //
  304.   // update stream length if length has been changed by str operators.
  305.   // Not done every time in case stream operation was the last operation 
  306.   // to change the length.
  307.   //
  308.    if (data->strChange) {
  309.        data->mystream->rdbuf()->set_len(data->curlength);
  310.        data->strChange=0;
  311.    };
  312.    return *data->mystream;
  313. };
  314.  
  315. int str::length(void) const{
  316.    if ((!data->strChange) && (data->mystream))
  317.       setlength(data->mystream->rdbuf()->out_waiting());
  318.  
  319.    return data->curlength;
  320. };
  321.  
  322. str::~str (void){
  323.    STR_SUB_COUNTERS(ObjectCount)
  324.  
  325.    if (!(--data->refcount)){
  326.       STR_SUB_COUNTERS(AllocationCount)
  327.  
  328.       delete data->mystream;
  329.       delete data;
  330.    };
  331. };
  332.  
  333. //
  334. // return (const char *)
  335. //
  336. str::operator const char * () const{
  337.    data->buf[length()] = 0;
  338.    return data->buf;
  339. };
  340.  
  341. const char * str::operator()(int index) const   
  342. {
  343.    return  (*this)() + index;
  344. }
  345.  
  346. char& str::operator[](int position)   // array indexing
  347. {
  348.    if (data->refcount>1) getNewBuffer(data->cursize);
  349.  
  350.    #ifndef SMART_STR_USER
  351.    //
  352.    // Force string to be null-terminated in case user
  353.    //   uses the "&" operator to pass a pointer (ie. &mystr[3])
  354.    //
  355.    if (!data->strChange) return *(char *)(*this)(position);
  356.          
  357.    #endif
  358.          
  359.    
  360.    return data->buf[position];
  361. }
  362.  
  363. int str::size(void) const{
  364.    return data->cursize;
  365. };
  366.                  
  367. //
  368. // str member = operators
  369. //
  370. str & str::_assign(const char * s, int len)
  371. {
  372.   // Get new buffer if necessary, but don't transfer contents.
  373.   // This is handled specially, so as to remove the unnecessary transfer.
  374.    if ((data->refcount>1) || (size()<len)) 
  375.       getNewBuffer( 0, max(size(),len) );
  376.  
  377.    if (!memsize_incr) len = min(len, size());
  378.    memcpy(data->buf, s, len);
  379.    setlength(len);
  380.    return *this;
  381.  
  382. };
  383.  
  384. str& str::operator = (const str& s){
  385.    if (this == &s) return *this;         // assignment to self
  386.    if (data == s.data) return *this;     // assignment to self
  387.  
  388.    if (!memsize_incr) return _assign(s, s.length());
  389.  
  390.    dynstream * prevStream=NULL;
  391.  
  392.    if (!(--data->refcount)) {  // deallocate old pointer
  393.       STR_SUB_COUNTERS(AllocationCount)
  394.  
  395.      //
  396.      // try to reuse this stream
  397.      //
  398.       prevStream = data->mystream;
  399.       if (s.data){
  400.          if (s.data->mystream) {
  401.             delete data->mystream;
  402.             prevStream = NULL;
  403.          }
  404.       }
  405.  
  406.       delete data;
  407.    };
  408.  
  409.    data = s.data;
  410.  
  411.    data->refcount++;
  412.  
  413.   //
  414.   // Map my stream to point to an existing stream using buffer data->buf
  415.   //
  416.    if (prevStream) {
  417.  
  418.          data->mystream = prevStream;  // what about previous mystream?
  419.  
  420.         //
  421.         // update s stream to map to new this stream
  422.         //
  423.          data->mystream->rdbuf()->setNewBuffer(data->buf, size());
  424.  
  425.         //
  426.         // update stream length next time stream is called for previous data
  427.         //
  428.          data->strChange = 1;
  429.  
  430.    }
  431.  
  432.  
  433.    return *this;
  434.  
  435. };
  436.  
  437.  
  438. str& str::operator = (const substr& s){
  439.    
  440.     int len = s.mystr->length() - s.posReplace;
  441.    if (len>=0) len = min(s.numReplace, len);
  442.    return _assign((*s.mystr)(s.posReplace), len);
  443. };
  444.  
  445. str& str::operator = (const char * s){
  446.    return _assign(s, strlen(s));
  447. };
  448.  
  449. str& str::assign(const char * s, int len){
  450.    return _assign(s, min(strlen(s), len));
  451. };
  452.  
  453. str& str::operator = (const char s){
  454.    return _assign(&s, 1);
  455. };
  456.  
  457. str & str::_concat(const char * s, int len)
  458. {
  459.    int mylen = length();
  460.  
  461.    _checkMemAllocation(mylen + len);
  462.  
  463.    if (!memsize_incr) len = min(len, size()-mylen);
  464.    memcpy(data->buf + mylen, s, len);    //concat
  465.    setlength(mylen+len);
  466.    return *this;
  467.  
  468. };
  469.  
  470.  
  471. //
  472. // str member += operators
  473. //
  474. str & str::operator += (const str& s){
  475.    if (!length()) return *this=s;
  476.    return _concat(s, s.length());
  477. };
  478.  
  479. str & str::operator += (const substr& s){
  480.    return _concat(&s.mystr->data->buf[s.posReplace], s.length());
  481. };
  482.  
  483. str & str::operator += (const char * s){
  484.    return _concat(s, strlen(s));
  485. };
  486.  
  487. str & str::operator += (const char s){
  488.    return _concat(&s, 1);
  489. };
  490.  
  491.  
  492. //
  493. // str member << operators
  494. //
  495. str& str::operator << (const str& s)    { return *this+=s;};
  496. str& str::operator << (const substr& s) { return *this+=s;};
  497. str& str::operator << (const char * s)  { return *this+=s;};
  498. str& str::operator << (const char s)    { return *this+=s;};
  499. str& str::operator << (const int s){
  500.    stream() << s;
  501.    return *this;
  502. };
  503. str& str::operator << (const long s){
  504.    stream() << s;
  505.    return *this;
  506. };
  507.  
  508. //
  509. // str member + operators
  510. //
  511. str str::operator+(const _SUBSTR & b) const{ return str(*this,b); };
  512. str str::operator+(const str&b)           const{ return str(*this,b); };
  513. str str::operator+(const char * b)        const{ return str(*this,b); };
  514. str str::operator+(const char b) const{
  515.    char buf[2];
  516.    buf[0]=b;
  517.    buf[1]=0;
  518.  
  519.    return str(*this,buf);
  520. };
  521.  
  522.  
  523. // 
  524. // istream/ostream friend functions
  525. //
  526. istream& operator >> (istream& stream, str & s){
  527.    if (s.memsize_init>256){   // Use str's current data buffer
  528.       s = " ";                // Gets new buffer if neccessary (ie. reference)
  529.       stream.getline(s.data->buf, s.size());
  530.       s.setlength(stream.gcount());
  531.       if (s[s.length()]==10)  // retrieve to end of line
  532.          s.setlength(s.length()-1);
  533.    }
  534.    else {
  535.       char buf[256];
  536.       stream.getline(buf, 256);
  537.       if (buf[stream.gcount()-1]==10)  // retrieve to end of line
  538.          buf[stream.gcount()-1]=0;
  539.  
  540.       s = buf;
  541.    };
  542.  
  543.    return stream;
  544. };
  545.  
  546. istream& str::read(istream& stream, int count)
  547. {
  548.     *this = " ";         // Gets new buffer if neccessary (ie. reference)
  549.     stream.read(data->buf, min(size(), count));
  550.    setlength(stream.gcount());
  551.  
  552.    return stream;
  553. };
  554.  
  555. ostream& operator << (ostream& stream, const str & s){
  556.    return stream << s();
  557. };
  558.  
  559.  
  560. str& str::lowercase()
  561. {
  562.   _checkMemAllocation();
  563.   strlwr(data->buf);
  564.   return *this;
  565. }
  566.  
  567. str& str::uppercase()
  568. {
  569.   _checkMemAllocation();
  570.   strupr(data->buf);
  571.   return *this;
  572. }
  573.  
  574. //
  575. // uppercase/lowercase friend functions
  576. //
  577. str uppercase(const char * s) {
  578.    str newstr(s);
  579.    strupr((char *)newstr());
  580.    return newstr;
  581. };
  582.  
  583. str lowercase(const char * s) {
  584.    str newstr(s);
  585.    strlwr((char *)newstr());
  586.    return newstr;
  587. };
  588.  
  589.  
  590. //
  591. // pad/strip
  592. //
  593. str& str::padRight(int padsize, char padchar)
  594.    return pad(padsize, right, padchar);
  595. }
  596. str& str::padLeft(int padsize, char padchar)
  597.    return pad(padsize, left, padchar);
  598. }
  599. str& str::padBoth(int padsize, char padchar)
  600.    return pad(padsize, both, padchar);
  601. }
  602.  
  603. str& str::pad(int padsize, PadStripT t, char padchar){
  604.  
  605.    int len = length();
  606.  
  607.    if (len<padsize) {
  608.  
  609.       _checkMemAllocation(padsize);
  610.       if (!memsize_incr) padsize = min(padsize, size());
  611.       
  612.       if (t == right)
  613.          memset(&data->buf[len], padchar, padsize-len);
  614.  
  615.       else if (t == both){
  616.          int len1 = (padsize-len)/2;
  617.          int len2 = (padsize-len+1)/2;
  618.  
  619.          memmove(&data->buf[len1], &data->buf, len);
  620.          memset(&data->buf[0], padchar, len1);
  621.          memset(&data->buf[len+len1], padchar, len2);
  622.       }
  623.  
  624.       else{
  625.          int len1 = (padsize-len);
  626.  
  627.          memmove(&data->buf[len1], &data->buf, len);
  628.          memset(&data->buf[0], padchar, len1);
  629.       }
  630.  
  631.       setlength(padsize);
  632.    };
  633.  
  634.    return *this;
  635. }
  636.  
  637. str& str::stripTrailing(const char * stripchars)
  638. {
  639.    return strip(trailing, stripchars);
  640. }
  641. str& str::stripLeading(const char * stripchars)
  642. {
  643.    return strip(leading, stripchars);
  644. }
  645. str& str::stripBoth(const char * stripchars)
  646. {
  647.    return strip(both, stripchars);
  648. }
  649. str& str::strip(PadStripT t, char stripchar){
  650.  
  651.    int len = length();
  652.    int start = 0;
  653.    int end = len-1;
  654.  
  655.    if (end<0) return *this;
  656.  
  657.    if ((t == leading) || (t==both)){
  658.       for (; start<=end; start++)
  659.          if (data->buf[start] != stripchar) break;
  660.    };
  661.  
  662.    if ((t == trailing) || (t==both)){
  663.        if (data->buf[end] == stripchar) {
  664.           for (; end >= start; end--){
  665.              if (data->buf[end] != stripchar) break;
  666.           };
  667.        };
  668.    };
  669.  
  670.    if ((end-start+1)<len)
  671.    {
  672.       _checkMemAllocation();
  673.       if (start) memmove(&data->buf[0], &data->buf[start], end-start+1);
  674.       setlength(end-start+1);
  675.    };
  676.  
  677.    return *this;
  678.  
  679. };
  680.  
  681.  
  682. str& str::strip(PadStripT t, const char * stripchars){
  683.  
  684.    int len = length();
  685.    int start = 0;
  686.    int end = len-1;
  687.  
  688.    if (end<0) return *this;
  689.  
  690.  
  691.    if ((t == leading) || (t==both)){
  692.  
  693.       int pos = strspn((*this)(), stripchars);
  694.       if (pos>0) start += pos;
  695.  
  696.    };
  697.  
  698.    if ((t == trailing) || (t==both)){
  699.  
  700.      if (strchr(stripchars, data->buf[end])){
  701.         for (; end>=start; end--){
  702.            if (!strchr(stripchars, data->buf[end])) break;
  703.         }
  704.      }
  705.    };
  706.  
  707.    if ((end-start+1)<len)
  708.    {
  709.       _checkMemAllocation();
  710.       if (start) memmove(&data->buf[0], &data->buf[start], end-start+1);
  711.       setlength(end-start+1);
  712.    };
  713.  
  714.    return *this;
  715. };
  716.  
  717. str pad(str s, int padsize, str::PadStripT t, char padchar){
  718.    return s.pad(padsize, t, padchar);
  719. };
  720.  
  721. str strip(str s, str::PadStripT t, const char * stripchars){
  722.    return s.strip(t, stripchars);
  723. };
  724.  
  725. str strip(str s, str::PadStripT t, char stripchar){
  726.    return s.strip(t, stripchar);
  727. };
  728.  
  729. str itostr(int val){
  730.    str s;
  731.    s << val;
  732.    return s;
  733. }
  734.  
  735. str ltostr(long val){
  736.     str s;
  737.     s << val;
  738.     return s;
  739. }
  740.  
  741. int strtoi(const str& s)   // convert str to int
  742. {
  743.     return atoi(s);
  744. }
  745. long strtol(const str& s)   // convert str to int
  746. {
  747.     return atol(s);
  748. }
  749.  
  750. //
  751. // insert/remove
  752. //
  753. int str::insert(int pos, char ch){
  754.     char tempstr[2];
  755.     tempstr[0] = ch;
  756.     tempstr[1] = 0;
  757.     return insert(pos, tempstr);
  758. }
  759.  
  760. int str::count(const char ch, int start) const
  761. {
  762.  
  763.    int count=0;
  764.    const char * curPtr= (*this)(start);
  765.  
  766.    do {
  767.        curPtr = strchr(curPtr+1, ch);
  768.        if (curPtr) count++;
  769.        else break;
  770.    } while (1);
  771.  
  772.    return count;
  773. }
  774.  
  775. int str::insert(int pos, const char * insertStr){
  776.    int len = length();
  777.    int afterPos = len+1-pos;  // number of characters following pos
  778.  
  779.    if (afterPos<0) return 0;  // out of range
  780.  
  781.    int insertLen = strlen(insertStr);
  782.    _checkMemAllocation( len+insertLen );
  783.  
  784.    if (!memsize_incr) insertLen = min(insertLen, size()-len);
  785.  
  786.    if (insertLen){
  787.      if (afterPos)
  788.         memmove(&data->buf[pos + insertLen], &data->buf[pos], afterPos);
  789.      memmove(&data->buf[pos], insertStr, insertLen);
  790.      setlength(len+insertLen);
  791.      return 1;
  792.    }
  793.    else return 0;
  794. };
  795.  
  796. void str::remove(int pos, int numdel){
  797.    int len = length();
  798.    if (pos>=len) return;
  799.    _checkMemAllocation();
  800.  
  801.    numdel = min(numdel, len-pos); 
  802.    memmove(&data->buf[pos], &data->buf[pos+numdel], len-(numdel+pos));
  803.    setlength(len-numdel);
  804. };   
  805.  
  806. void str::setLength(int len)            // update the current length
  807. {
  808.    _checkMemAllocation(len);
  809.    if (len<=size()) setlength(len);
  810. }
  811.  
  812. //
  813. // substr member operators/functions
  814. //
  815. _SUBSTR::substr(const str * data, int AposReplace, int AnumReplace):
  816.    mystr((str *)data), posReplace(AposReplace), numReplace(AnumReplace){};
  817.  
  818. _SUBSTR str::operator()(int pos, int numreplace)
  819. {
  820.    return substr(this, pos, numreplace);
  821. }
  822.  
  823. const _SUBSTR str::operator()(int pos, int numreplace) const
  824. {
  825.    return substr(this, pos, numreplace);
  826. }
  827.  
  828. int _SUBSTR::length(void) const{
  829.    return min(numReplace, max(0, mystr->length()-posReplace) );
  830. };
  831.  
  832.  
  833. str & _SUBSTR::operator = (const char * s){
  834.    if (posReplace<0) return *this->mystr;
  835.  
  836.    if (strlen(s)==length()){
  837.       mystr->_checkMemAllocation();
  838.       memcpy(&mystr->data->buf[posReplace], s, length());
  839.    }
  840.    else {
  841.       mystr->remove(posReplace, numReplace);
  842.       mystr->insert(posReplace, s);
  843.    };
  844.    return *this->mystr;
  845. };
  846.  
  847. str & _SUBSTR::operator = (const substr& s){
  848.    return *this = *s.mystr;
  849. };
  850.  
  851. str _SUBSTR::operator+(const char * s) const{
  852.    return str(*this, s);
  853. };
  854.  
  855. str _SUBSTR::operator+(const substr& s) const{
  856.    return str(*this, s);
  857. };
  858.  
  859. int _SUBSTR::compare(const char * s) const{
  860.    return mystr->strncmp((*this->mystr)(posReplace), s, numReplace);
  861. };
  862.  
  863. int _SUBSTR::compare(const substr& s) const{
  864.    int len = min(numReplace, s.numReplace);
  865.    return mystr->strncmp((*this->mystr)(posReplace), (*s.mystr)(s.posReplace), len);
  866. };
  867.  
  868. int _SUBSTR::operator==(const char *s) const{ return compare(s)==0; };
  869. int _SUBSTR::operator<=(const char *s) const{ return compare(s)<=0; };
  870. int _SUBSTR::operator>=(const char *s) const{ return compare(s)>=0; };
  871. int _SUBSTR::operator!=(const char *s) const{ return compare(s)!=0; };
  872. int _SUBSTR::operator< (const char *s) const{ return compare(s)< 0; };
  873. int _SUBSTR::operator> (const char *s) const{ return compare(s)> 0; };
  874.  
  875. int _SUBSTR::operator==(const substr& s) const{ return compare(s)==0; };
  876. int _SUBSTR::operator<=(const substr& s) const{ return compare(s)<=0; };
  877. int _SUBSTR::operator>=(const substr& s) const{ return compare(s)>=0; };
  878. int _SUBSTR::operator!=(const substr& s) const{ return compare(s)!=0; };
  879. int _SUBSTR::operator< (const substr& s) const{ return compare(s)< 0; };
  880. int _SUBSTR::operator> (const substr& s) const{ return compare(s)> 0; };
  881.  
  882. _SUBSTR::operator str() const{
  883.   str temp;
  884.   temp.assign((*(mystr))(posReplace), numReplace);
  885.   return temp;
  886. };
  887.  
  888. int str::_checkMemAllocation(int requiredLen){
  889.    if ((data->refcount<=1) && (size()>=requiredLen)) return 1;
  890.  
  891.    return (getNewBuffer(max(size(), requiredLen))!=NULL);
  892. };
  893.  
  894.  
  895. //
  896. // Case sensitivity member functions
  897. //
  898. int str::caseSensitive(void) const { return !(flags & ICASE); }
  899.  
  900. void str::setCaseSensitive(int val) 
  901.   if (val) flags &= !ICASE;
  902.   else flags |= ICASE; 
  903. }
  904.  
  905. void str::setdefaultCaseSensitive(int val)
  906. {
  907.   if (val) defaultFlags &= !ICASE;
  908.   else defaultFlags |= ICASE; 
  909. }
  910.  
  911. //
  912. // Friend/Global str relational operators
  913. //
  914. str operator + (const char *a, const str&b)        {  return str(a,b); };
  915. str operator + (const char *a, const _SUBSTR&b){  return str(a,b); };
  916.  
  917. int compare(const char * a, const str & b) {return ( b.strcmp(a, b) );};
  918. int compare(const str& a,   const str & b) {return ( a.strcmp(a, b) );};
  919. int compare(const str& a,  const char * b) {return ( a.strcmp(a, b) );};
  920.  
  921. int operator ==(const char *a, const str&b){return (compare(a,b) == 0); };
  922. int operator >=(const char *a, const str&b){return (compare(a,b) >= 0); };
  923. int operator <=(const char *a, const str&b){return (compare(a,b) <= 0); };
  924. int operator !=(const char *a, const str&b){return (compare(a,b) != 0); };
  925. int operator > (const char *a, const str&b){return (compare(a,b) > 0); };
  926. int operator < (const char *a, const str&b){return (compare(a,b) < 0);};
  927.  
  928. int operator ==(const char *a, const _SUBSTR &b){ return b==a; };
  929. int operator >=(const char *a, const _SUBSTR &b){ return b<=a; };
  930. int operator <=(const char *a, const _SUBSTR &b){ return b>=a; };
  931. int operator !=(const char *a, const _SUBSTR &b){ return b!=a; };
  932. int operator > (const char *a, const _SUBSTR &b){ return b<a;  };
  933. int operator < (const char *a, const _SUBSTR &b){ return b>a;  };
  934.  
  935. //
  936. // Member str relational operators
  937. //
  938. int str::operator==(const char *b) const{ return (compare(*this,b) == 0); };
  939. int str::operator<=(const char *b) const{ return (compare(*this,b) <= 0); };
  940. int str::operator>=(const char *b) const{ return (compare(*this,b) >= 0); };
  941. int str::operator!=(const char *b) const{ return (compare(*this,b) != 0); };
  942. int str::operator> (const char *b) const{ return (compare(*this,b) > 0); };
  943. int str::operator< (const char *b) const{ return (compare(*this,b) < 0); };
  944.  
  945. int str::operator==(const str &b) const{ return (compare(*this,b) == 0); };
  946. int str::operator<=(const str &b) const{ return (compare(*this,b) <= 0); };
  947. int str::operator>=(const str &b) const{ return (compare(*this,b) >= 0); };
  948. int str::operator!=(const str &b) const{ return (compare(*this,b) != 0); };
  949. int str::operator> (const str &b) const{ return (compare(*this,b) > 0); };
  950. int str::operator< (const str &b) const{ return (compare(*this,b) < 0); };
  951.  
  952.  
  953. int str::strncmp(const char * s1, const char * s2, int n) const{
  954.    if (caseSensitive()) return ::strncmp(s1,s2,n);
  955.    else return ::strnicmp(s1,s2,n);
  956. };
  957.  
  958. int str::strcmp(const char * s1, const char * s2) const{
  959.    if (caseSensitive()) return ::strcmp(s1,s2);
  960.    else return ::stricmp(s1,s2);
  961. };
  962.  
  963. int str::defaultFlags = 0;
  964.  
  965. unsigned str::HashValue() const  // use Borland's String hash function
  966. {
  967.      unsigned value = 7;  // seed
  968.     for( int i = 0; i < length(); i++ )
  969.         {
  970.         if (caseSensitive()) value ^= data->buf[i];
  971.         else value ^= toupper(data->buf[i]);
  972.         value = _rotl( value, 1 );
  973.         }
  974.     return value;
  975. }
  976.  
  977. #ifdef DEBUG_STR
  978. int str::dynstreamCount=0;
  979. int str::ObjectCount=0;
  980. int str::AllocationCount=0;
  981. int str::TotalObjectCount=0;
  982. int str::TotalAllocationCount=0;
  983. #endif
  984.  
  985.